﻿/**
 * @file Translation.h
 * @brief 简易FTL地址转换模块，负责LBA到NAND地址的映射。
 */
#ifndef __Translation_h__
#define __Translation_h__

#include "Nand/Hal/NandHal.h"

/**
 * @namespace SimpleFtlTranslation
 * @brief 简易FTL地址转换相关函数和参数。
 */
namespace SimpleFtlTranslation
{
    static U8 _SectorSizeInBit;         /**< 扇区大小（bit） */
    static U8 _SectorsPerPage;          /**< 每页扇区数 */
    static NandHal::Geometry _Geometry; /**< NAND设备几何参数 */

    /**
     * @brief LBA到NAND地址转换。
     * @param lba 逻辑块地址
     * @param sectorCount 扇区数
     * @param nandAddress 输出NAND地址结构体
     * @param nextLba 输出下一个LBA
     * @param remainSectorCount 输出剩余扇区数
     */
    static inline void LbaToNandAddress(const U32 &lba, const U32 &sectorCount,
                                        NandHal::NandAddress &nandAddress, U32 &nextLba, U32 &remainSectorCount)
    {
        U32 pageIndex = lba / (_Geometry.BytesPerPage >> _SectorSizeInBit);
        nandAddress.Channel._ = pageIndex % _Geometry.ChannelCount;
        nandAddress.Device._ = (pageIndex / _Geometry.ChannelCount) % _Geometry.DevicesPerChannel;
        nandAddress.Page._ = ((pageIndex / _Geometry.ChannelCount) / _Geometry.DevicesPerChannel) % _Geometry.PagesPerBlock;
        nandAddress.Block._ = (((pageIndex / _Geometry.ChannelCount) / _Geometry.DevicesPerChannel) / _Geometry.PagesPerBlock);
        nandAddress.Sector._ = lba % _SectorsPerPage;

        if (nandAddress.Sector._ + sectorCount <= _SectorsPerPage)
        {
            nandAddress.SectorCount._ = sectorCount;
        }
        else
        {
            nandAddress.SectorCount._ = _SectorsPerPage - nandAddress.Sector._;
        }

        nextLba = lba + nandAddress.SectorCount._;
        remainSectorCount = sectorCount - nandAddress.SectorCount._;
    }

    /**
     * @brief 设置NAND设备几何参数。
     * @param geometry 几何参数结构体
     */
    static inline void SetGeometry(const NandHal::Geometry &geometry)
    {
        _Geometry = geometry;
    }

    /**
     * @brief 设置扇区大小（bit），并计算每页扇区数。
     * @param sectorSizeInBit 扇区大小（bit）
     */
    static inline void SetSectorSize(const U8 &sectorSizeInBit)
    {
        _SectorSizeInBit = sectorSizeInBit;
        _SectorsPerPage = _Geometry.BytesPerPage >> _SectorSizeInBit;
    }
};

#endif